﻿using System;
using System.Linq;
using System.Threading.Tasks;
using CoreCms.Net.Configuration;
using CoreCms.Net.IServices;
using CoreCms.Net.Loging;
using CoreCms.Net.Model.Entities;
using CoreCms.Net.Utility.Extensions;
using CoreCms.Net.Utility.Helper;
using InitQ.Abstractions;
using InitQ.Attributes;
using Microsoft.Extensions.DependencyInjection;
using SqlSugar;

namespace CoreCms.Net.RedisMQ
{
    /// <summary>
    /// 售后审核通过后对积分的返还处理
    /// </summary>
    public class AfterSalesReviewForPointSubscribe : IRedisSubscribe
    {
        private readonly IServiceProvider _serviceProvider;

        public AfterSalesReviewForPointSubscribe(IServiceProvider serviceProvider)
        {
            _serviceProvider = serviceProvider;
        }

        /// <summary>
        /// 售后审核通过后对积分的返还处理
        /// </summary>
        /// <param name="msg"></param>
        /// <returns></returns>
        [Subscribe(RedisMessageQueueKey.AfterSalesReviewForPoint)]

        private async Task AfterSalesReviewForPointSubscribeCommand(string msg)
        {
            try
            {
                if (string.IsNullOrEmpty(msg))
                {
                    NLogUtil.WriteAll(NLog.LogLevel.Error, LogType.RedisMessageQueue, "售后审核通过后积分处理", "审核单编号获取失败");
                    return;
                }
                //使用服务驱动器取服务，防止autofac出现循环注入
                using var container = _serviceProvider.CreateScope();
                var _aftersalesServices = container.ServiceProvider.GetService<ICoreCmsBillAftersalesServices>();
                var _orderServices = container.ServiceProvider.GetService<ICoreCmsOrderServices>();
                var _orderItemServices = container.ServiceProvider.GetService<ICoreCmsOrderItemServices>();
                var _aftersalesItemServices = container.ServiceProvider.GetService<ICoreCmsBillAftersalesItemServices>();
                var _productsServices = container.ServiceProvider.GetService<ICoreCmsProductsServices>();
                var _settingServices = container.ServiceProvider.GetService<ICoreCmsSettingServices>();
                var _userServices = container.ServiceProvider.GetService<ICoreCmsUserServices>();
                var _userPointLogServices = container.ServiceProvider.GetService<ICoreCmsUserPointLogServices>();

                var info = await _aftersalesServices.QueryByClauseAsync(p => p.aftersalesId == msg, true);
                if (info != null)
                {
                    var order = await _orderServices.QueryByClauseAsync(p => p.orderId == info.orderId, true);
                    if (order == null)
                    {
                        NLogUtil.WriteAll(NLog.LogLevel.Error, LogType.RedisMessageQueue, "售后审核通过后积分处理", "订单数据获取失败");
                        return;
                    }
                    if (order.point == 0)
                    {
                        NLogUtil.WriteAll(NLog.LogLevel.Info, LogType.RedisMessageQueue, "售后审核通过后积分处理", "未使用积分无需处理");
                        return;
                    }
                    var userModel = await _userServices.QueryByClauseAsync(p => p.id == order.userId, true);
                    if (userModel == null)
                    {
                        NLogUtil.WriteAll(NLog.LogLevel.Info, LogType.RedisMessageQueue, "售后审核通过后积分处理", "用户信息获取失败");
                        return;
                    }

                    //获取售后明细
                    var aftersalesItems = await _aftersalesItemServices.QueryListByClauseAsync(p => p.aftersalesId == info.aftersalesId, p => p.id, OrderByType.Asc, true);
                    if (aftersalesItems == null)
                    {
                        NLogUtil.WriteAll(NLog.LogLevel.Info, LogType.RedisMessageQueue, "售后审核通过后积分处理", "售后明细获取失败");
                        return;
                    }
                    //获取售后货品信息
                    var productIds = aftersalesItems.Select(p => p.productId).ToList();
                    var orderItem = await _orderItemServices.QueryListByClauseAsync(p => p.orderId == order.orderId, p => p.id, OrderByType.Asc, true);
                    var products = await _productsServices.QueryListByClauseAsync(p => productIds.Contains(p.id), p => p.id, OrderByType.Asc, true);

                    var allConfigs = await _settingServices.GetConfigDictionaries();
                    var pointExchangeModel = CommonHelper.GetConfigDictionary(allConfigs, SystemSettingConstVars.PointExchangeModel).ObjectToInt();    //积分模式 1全局2单品
                    var pointDiscountedProportion = CommonHelper.GetConfigDictionary(allConfigs, SystemSettingConstVars.PointDiscountedProportion).ObjectToInt();    //多少积分等于1元钱。

                    //var pointDiscounted = Math.Round(pointDiscountedProportion / 100, 4);

                    //var ordersPointProportion = CommonHelper.GetConfigDictionary(allConfigs, SystemSettingConstVars.OrdersPointProportion).ObjectToInt();    //积分使用比例  全局模式下一个订单最多可以使用多少比例的积分
                    decimal point = 0;
                    foreach (var p in aftersalesItems)
                    {
                        var orderProduct = orderItem.Find(x => x.productId == p.productId);
                        if (orderProduct == null)
                        {
                            continue;
                        };
                        var product = products.Find(x => x.id == p.productId);
                        if (product == null)
                        {
                            continue;
                        };
                        //如果是全局模式（根据比例来退还积分）
                        if (pointExchangeModel == 1)
                        {
                            //可能存在就是根本不是全积分抵扣，而是订单实际在不够积分的情况下，抵扣了多少金额。那么统一就根据订单的比例来计算，更加精准，（这里的总金额是实际支付金额，去掉了优惠）
                            //如果订单实际支付金额是0的话，那就是全积分。
                            var practicalProportion = order.orderAmount <= 0 ? 1 : Math.Round(order.pointMoney / order.goodsAmount, 4);

                            //未发货的商品库存调整,如果订单未发货或者部分发货，并且用户未收到商品的情况下
                            if (order.shipStatus is (int)GlobalEnumVars.OrderShipStatus.No or (int)GlobalEnumVars.OrderShipStatus.PartialYes &&
                                info.type == (int)GlobalEnumVars.BillAftersalesIsReceive.Refund && p.nums == 0)
                            {
                                point += orderProduct.price * practicalProportion * orderProduct.nums * pointDiscountedProportion;
                            }
                            else
                            {
                                //获取货品金额*积分使用比例*数量*积分折现比例=积分抵扣的金额应该可以兑换的积分。
                                point += orderProduct.price * practicalProportion * p.nums * pointDiscountedProportion;
                            }

                        }
                        //如果是单品模式
                        else if (pointExchangeModel == 2)
                        {
                            //未发货的商品库存调整,如果订单未发货或者部分发货，并且用户未收到商品的情况下
                            if (order.shipStatus is (int)GlobalEnumVars.OrderShipStatus.No or (int)GlobalEnumVars.OrderShipStatus.PartialYes &&
                                info.type == (int)GlobalEnumVars.BillAftersalesIsReceive.Refund && p.nums == 0)
                            {
                                point += product.pointsDeduction * orderProduct.nums * pointDiscountedProportion;
                            }
                            else
                            {
                                //单品模式只能是全积分抵扣或者全金额支付。所以直接按照扣掉的金额还原积分即可。
                                point += product.pointsDeduction * p.nums * pointDiscountedProportion;
                            }
                        }
                    }

                    //为了计算比例情况下，增加精度，全局模式下用了4位小数。这里四色五入积分差异控制小点。
                    var practicalPoint = Convert.ToInt32(point);

                    var newPoint = practicalPoint + userModel.point;

                    var pointLog = new CoreCmsUserPointLog
                    {
                        userId = userModel.id,
                        type = (int)GlobalEnumVars.UserPointSourceTypes.PointRefundReturn,
                        num = practicalPoint,
                        balance = newPoint,
                        remarks = "售后单：" + info.aftersalesId + "退还积分",
                        createTime = DateTime.Now
                    };

                    var id = await _userPointLogServices.InsertAsync(pointLog);
                    if (id > 0)
                    {
                        await _userServices.UpdateAsync(p => new CoreCmsUser() { point = p.point + practicalPoint }, p => p.id == userModel.id);
                    }
                    NLogUtil.WriteAll(NLog.LogLevel.Info, LogType.RedisMessageQueue, "售后审核通过后积分处理", msg);
                }
                else
                {
                    NLogUtil.WriteAll(NLog.LogLevel.Info, LogType.RedisMessageQueue, "售后审核通过后积分处理", "售后单查询失败");
                }
            }
            catch (Exception ex)
            {
                NLogUtil.WriteAll(NLog.LogLevel.Error, LogType.RedisMessageQueue, "售后审核通过后积分处理", msg, ex);
                throw;
            }
            await Task.CompletedTask;
        }




    }
}
